I-폐쇄망 k8s 설치 개요
개요
인터넷과 연결할 수 없는 네트워크 환경을 폐쇄망, 혹은 에어갭이라고 부른다.
이 노트는 쿠버네티스를 에어갭 환경에서 구축하는 방법에 대한 전반적인 개요를 담는다.
클러스터를 구축하는데 있어서 중요한 것은 노드를 어떻게 부트스트랩하고 조인시키는가의 문제이다.
여기에서 폐쇄망 환경이라는 특별 조건이 추가되면 어떻게 필요한 데이터들을 내부망으로 전달하는가의 문제가 추가된다.
후자의 문제는 비단 구축할 때만 고려할 사항이 아니라 앞으로 클러스터를 운영하면서 끊임없이 고려해야 할 문제가 되므로 이에 대한 적절한 전략과 솔루션을 마련할 필요가 있다.
해당 문제는 아래에서 더 구체화시키고, 먼저 클러스터를 구축하는데 필요한 것들이 무엇이 있는지 파악해본다.
클러스터 부트스트랩
먼저 어느 환경에서든 클러스터를 구축하는 기본적인 과정을 정리해본다.
노드 세팅
머신이 노드로서 기능하기 위해 필요한 사항은 다음과 같다.
- 네트워크
- 고유한 호스트네임, MAC 주소, product_uuid
- 시간 동기화(대체로 ntp)
- 커널 모듈 - modprobe를 통해 수동 로드 및
/etc/modules-load.d
에 영구 세팅, 관련 변수는 sysctl로 수동 적용 및/etc/sysctl.d
에 영구 세팅[1]net.ipv4(6).ip_forward = 1
- 패킷 포워딩- br_netfilter 모듈
net.bridge.bridge-nf-call-ip(6)tables = 1
- 브릿지 인터페이스를 지나는 패킷도 L3까지 올라와 iptables의 영향 받도록 설정
- conntrack 모듈
- overlay 모듈 - 컨테이너 런타임에서 overlay 파일시스템 활용
- 컨테이너 런타임 - CRI
- kubelet이 연결할 수 있는 CRI 인터페이스(대체로 UDS)를 제공하는 컨테이너 관리 툴이 필요하다.
- Containerd, CRI-O가 대표적
- 컨테이너 런타임 - OCI
- CRI 구현 런타임 하위의 OCI 스펙을 구현하는 런타임이 필요하다.
- 이들은 여러 개 병행 운용할 수 있으며, CRI에서 설정으로 넣어줄 수 있다.
- 추가 고려사항 - 설정할 때 kubelet과 런타임에서 지정하는 cgroupDriver는 일치해야 한다.
- 기타
- SElinux permissive 모드
- 설정하지 않으면 컨테이너가 호스트 파일시스템에 접근할 수 없다.
- enforcing 모드를 유지하며 필요한 컨테이너만 설정하도록 보안을 강화할 수도 있다.
- firewalld disable - 아니면
firewall-cmd --permanent --add-port=6443/tcp
의 방식으로 최소 포트 개방- 6443, 2379-2380, 10250, 10251, 10252, 10255
- swap 메모리 off - 현 버전 기준 필수는 아니나, 비스왑 메모리와 구분지어 세팅 관리해야 하는 번거로움은 있다.
- SElinux permissive 모드
br_netfilter는 기본 컨테이너 네트워킹에서도 필요한 사항이나, cillium으로 kube-proxy까지 대체하는 환경에서 conntrack 모듈이 필요한지는 조금 더 연구 필요
부트스트랩
쿠버네티스 클러스터를 구축하는 기본적인 툴인 kubeadm을 통해 클러스터가 구동되기 위해 필요한 과정을 살펴볼 수 있다.[7]
kubeadm이 실제로 수행하는 절차 중 커스텀이 가능하다 생각되는 것들은 기울임했다.
- 프라플라이트 - 노드 상태 확인
- 인증서 생성 단계 -
--cert-dir
로 설정된 곳에 저장되는데, 보통/etc/kubenetes/pki
- 루트 CA
- api-sever
- apiserver-kubelet-client - api서버가 kubelet과 통신
- front-proxy-ca - 프론트 프록시가 있을 때 이를 위한 루트 인증서
- front-proxy-client - 프록시 클라이언트를 위한 인증서
- etcd-ca
- etcd-server - etcd 단일 엔드포인트
- etcd-peer - etcd 다중화 시 서로 통신하기 위한 인증서
- etcd-healthcheck-client - etcd 헬스체크를 하기 위한 liveness probe용 인증서
- apiserver-etcd-client - api 서버가 etcd와 통신
- sa - 서비스 어카운트를 서명하기 위한 개인, 공개키
- kubeconfig 생성 단계 -
/etc/kubernetes
에 conf라는 확장자를 달고 저장된다.- admin - 관리자와 kubeadm 사용
- super-admin - 슈퍼 관리자 사용 - RBAC 적용을 받지 않는 루트 유저
- kubelet - 노드 부트스트랩 시에만 임시 사용
- controller-manager
- scheduler
- 정적 파드 양식 생성
- etcd, apiserver, controller-manager, scheduler
- kubelet 설정 세팅 후 restart
- 설정 파일 업로드
- kubelet, kubeadm의 설정 파일을 configmap으로 업로드
- 인증서들을 kubeadm-certs에 업로드
- 컨트롤 플레인 마킹 - 라벨, 테인트
- join용 토큰 생성 및 kubelet 최종 - kubelet이 클러스터에 처음 연결될 때 사용,
- 이후 kubelet은 클러스터에 CSR을 날려 실제 사용할 인증서를 받아온다.
- 인증서 갱신 활성화
- 애드온 - coredns, kube-proxy
- join 커맨드 출력
클러스터 구축에 필요한 패키지, 이미지
다음으로 실제로 클러스터가 돌아가기 위해 필요한 구성품을 알아본다.
들어가기에 앞서, 어떤 툴을 어떻게 배치할지에 대한 방법은 너무나도 다양하다.
컨트롤 플레인의 모든 요소를 일반 바이너리로 실행해서 systemd에 등록하는 것도 가능한 한편,
컨테이너 이미지 레지스트리를 컨테이너로 띄워도 된다.
일일히 설명하기 구차한 관계로 무조건 방법이 고정돼있는 것을 제외해서는 부연하지 않는다.
구성도를 간단히 하고자 단일 노드로 구성한 클러스터를 가정해보면,
하나의 노드가 클러스터로 동작하기 위해 필수적으로 필요한 것은 크게 두 가지로 구분지을 수 있다.
- 리눅스 패키지 - 클러스터에 컨테이너가 실행되고 관리될 수 있도록 하는 각종 툴
- 컨테이너 이미지 - 클러스터를 관리하는 기본 컨트롤 플레인 컴포넌트
폐쇄망에서는 두 종류의 파일들을 서빙할 수 있는 별도의 레지스트리, 레포지토리를 구성해야 한다.
리눅스 패키지
클러스터에 컨테이너가 돌아가기 위해 컨테이너를 실행해야 하는 바이너리가 여기에 해당한다.
다음의 것들은 컨테이너로 띄울 수 없어 패키지 형태로 받아서 사용한다.
- CRI - CRI-O or Containerd
- OCI - 기본 runc
- kubelet
- cni - cni 프로바이더가 실행할 저수준 바이너리 구현체[8]
노드 내부에 자체적으로 만든 미러 레포에서 패키지를 가져오도록 /etc/yum.repos.d
와 같은 저장소 설정을 추가해줘야 한다.
컨테이너 이미지
컨테이너 런타임과 kubelet을 제외하면 다른 모든 것들은 컨테이너로 구동시켜 운용이 가능하다.
물론 이것들도 일반적인 실행 가능한 바이너리로 가져와서 구동하는 것도 가능하나, 필수적이진 않다.
(참고로 kubespray를 통해 클러스터를 구축한다면 etcd는 바이너리로 배치된다.)
조금 더 분류하자면,
- 정적 파드로 배치
- kube-apiserver, kube-scheduler, kube-controller-manager, Etcd
- 기본 파드로 배치
- kube-proxy, Core DNS
- CNI - cillium, flannel 등
- 기타
- pause container - 기본 파드가 배치되기 위한 전제조건
이들은 전부 tar 형태로 내부로 가져가 압축을 해제하며 컨테이너 이미지 형태로 로드해야 한다.
그리고 내부 레지스트리로 올려주면 된다.
참고로 이 두 작업은 컨테이너 런타임 구축이 선행되어야 한다.
이후 노드 컨테이너 런타임 설정에 미러 설정으로 미러 레지스트리 주소를 넣어주면, 이후 이미지를 풀 받는 일이 있을 때 자동으로 해당 레지스트리로부터 풀 받는다.
(워크로드 양식에 직접 미러 주소를 넣어도 되지만 일일히 이런 작업을 하는 것은 엄청난 비효율이다.)
저장소
인터넷에 연결될 수 있는 환경이라면 이것들은 공인 저장소를 통해 가져올 수 있으나, 폐쇄망에서는 이 모든 것들을 직접 파일로 집어 넣어주어야 한다.
이때 집어넣은 파일들을 편하게 배치하고 구동시키기 위해서 이미지 레지스트리, 패키지 레포지토리가 각각 요구된다.
엄밀하게 이러한 저장소는 필수가 아니지만 버전이나 의존성 등을 효과적으로 관리하고 구축 작업을 자동화하기 위해서는 거의 불가피한 선택이다.
망 내의 모든 노드가 접근할 수 있도록 내부에서 공개된 엔드포인트를 가지고 있는 편이 좋다.
- 이미지 레지스트리
- harbor나 일반 도커 레지스트리를 띄운다.
- 실행한 이후 파일 형태로 가져온 컨테이너 이미지들을 로드 후 푸시하는 작업이 필요하다.
- 리눅스 패키지
- nginx, HAproxy와 같이 간단하게 파일 서버 역할을 해줄 수 있으면 된다.
- 패키지 관리 툴이 이 저장소의 주소를 가리키도록 세팅해주어야 한다.
- 패키지 툴이 사용할 수 있는 규격으로 디렉토리에 메타데이터, 모듈 등의 세팅을 넣어주어야 한다.
리눅스 패키지의 경우 데비안 계열, 레드햇 계열 배포판에 따라 패키지 관리 툴이 다르다.
레드햇 계열(RHEL, Rocky, CentOS, AlmaLinux...)의 경우 기본 패키지 도구로 rpm이나 의존성 관리까지 가능한 yum, dnf를 사용한다.
번외 - 패키지 전달 전략 정리
리눅스(레드헷 기준) 패키지를 전달하는 방법은 다음의 방법들이 있으며, 아래로 갈수록 더 자동화되고 의존성과 버전 관리에 유리하다.
- tar
- 순수 명령어 압축해서 전달
- 어디에 어떤 파일이 있는지 알기 어렵고 의존성 관리 hard
- rpm
- 기본 명령어 패키징 수단
- 의존성 관리는 어려운 편[9]
- yum(dnf가 상위호환)
폐쇄망 클러스터 구축 툴 정리
폐쇄망에서 활용할 수 있는 다양한 툴의 종류를 정리한다.
각 툴에 따라 폐쇄망에 가져가야 할 추가적인 패키지가 필요하다.
아직 실습해보지 못한 다른 툴들은 조금 더 조사가 필요하다.
- 키보드 - 위 요소들을 가져와서 일일히 손으로 설치하면 된다.[15]
- kubeadm - 가장 기본적인 클러스터 구축 툴
- 각 노드에 직접 배치하고 마스터 노드라면 init, 워커 노드라면 join해 주어야 한다.
- 노드로서 기능시키기 위한 기본 세팅을 직접 진행해야 한다.
- 기본 구축 이후 CNI와 클러스터 위에 구동할 툴들을 일일히 배포해야 한다.
- Kubespray - 앤서블 플러그인
- ssh로 각 노드에 접근해 각종 설치에 필요한 사항을 자동화한다.
- 내부적으로는 kubeadm을 활용하고 있다.
- 특이사항으로 etcd를 systemd로 배치하는 것이 기본으로 활성화돼있다.
- api 서버 HA 구성할 때 프록시 파드까지 배치해준다.[16]
- CNI, CSI 등의 다른 툴까지 한꺼번에 구축할 수 있다.
- 앤서블을 이용하기 때문에 3.10 버전 이상의 파이썬과 관련 패키지도 함께 폐쇄망에 넣어주어야 한다.
- kurl[17]
- 클러스터 구축 스크립트와 모든 파일들을 간단한 url로 제공하는 오픈소스
- kubeadm 기반으로 몇가지 애드온들을 통합적으로 설치할 수 있다.
- 에어갭 환경을 위해 필요 파일을 전부 묶은 압축 파일을 제공하고 있다.
- kubesphere
- 클라우드 네이티브 통합 관리 솔루션으로 ui를 기반으로 툴을 설치하거나 클러스터를 관리하는데 사용
- Kubekey를 이용해서 설치[18]
- 클러스터를 정의하는 매니페스트, 매니페스트를 감싸는 아티팩트 개념을 이용해 필요한 파일을 패키징하고 적용한다.
- kubeops kosi - essential은 무료
- 클러스터 특화 소프트웨어 설치 툴.
- 헬름 사용성과 같이 투명하게 패키지를 전달하는 게 목적
- 하나의 패키지에 여러 이미지와 아티팩트를 묶음
- cluster api - https://jonnung.dev/kubernetes/2021/02/28/cluster-api-quickstart/
- 클러스터로 클러스터 만들기 https://if.kakao.com/2022/session/58
- 멀티 클러스터 구조를 만들거라면 고려는 해볼 만하다.
- 그런데 이미 노드 개수가 고정된 상태에서 정말 유의미한가?
- https://cluster-api.sigs.k8s.io/reference/providers
- 적절한 인프라 제공자가 필요하다.
- bring your own host https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost
- 관리 안 되고 있고 레드햇 계열 지원 명시되지 않음
- bring your own host https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost
- 클러스터로 클러스터 만들기 https://if.kakao.com/2022/session/58
폐쇄망 클러스터 구축 시나리오
이 부분은 폐쇄망 클러스터를 구축하는 간단한 시나리오를 생각해본 부분이다.
- 준비 단계
- 필요한 패키지, 이미지를 한꺼번에 묶은 번들 제작
- 초기 단계
- 필요한 패키지, 이미지를 서빙하는 간단한 서버 구축
- 이를 기반으로 초기 클러스터 구축
- 이후 하버, 넥서스 등의 아티팩트 저장소 구축
- 클러스터 내에 세울 것을 염두함
- 해당 저장소를 미러로 삼도록 모든 컨테이너 런타임 설정 변경
- 확장 단계
- 이후 추가되는 노드는 전부 내부 저장소 활용
- 운영 단계
- 이 부분은 아래 그림 참고
내부망에 아티팩트 스토어를 운영할 때 하버, 넥서스 등은 이미 클라이언트 인증과 이미지 취약점 스캔 등의 기능을 제공하고 있기에 외부와 접촉이 가능하더라도 기본적인 폐쇄망에서 기대되는 보안 수준을 만족할 수 있다.
이 경우 파일을 업데이트하거나 추가하는 운영자는 해당 경로를 통해 빠르게 폐쇄망으로 필요한 데이터들을 전송할 수 있다.
하지만 이러한 환경조차 허용하지 않는 엄격한 보안 요구가 있다면, 다음의 방법을 고려해볼 수 있다.
인터넷이 연결된 환경에 내부망에서 사용할 모든 데이터를 담은 저장소를 구축하고, 해당 저장소를 내부 저장소가 미러링하게 한다.[19]
하버 등의 저장소는 이러한 자동화된 복제 기능[20]을 제공하고 있기에 만약 두 저장소가 네트워크로 연결될 수 있다면 이 작업은 수월하게 이뤄질 수 있다.
물론 네트워크 연결이 되지 않는 환경이라면 데이터를 이동시키는 것은 usb를 든 사람이 될 것이다.
참고
데비안 계열
https://wimoney.tistory.com/entry/Kubernetes-쿠버네티스-설치Offline-기본-세팅#Podman_설치
바닐라 쿠버 설치 가이드로 잘 돼있긴 한데, 그닥 유용하진 않다.
https://drive.google.com/file/d/1P39WgYQGobx4LizjVLz9AY9F4pb2uyfe/view
https://medium.com/@taleghani/runc-vs-crun-in-containers-world-62b8143fd9d3 ↩︎
https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cgroupfs-cgroup-driver ↩︎
https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/#synopsis ↩︎
https://github.com/containernetworking/plugins?tab=readme-ov-file ↩︎
https://github.com/rpm-software-management/modulemd-tools ↩︎
https://github.com/kelseyhightower/kubernetes-the-hard-way ↩︎
https://kubesphere.io/docs/v3.3/installing-on-kubernetes/on-prem-kubernetes/install-ks-on-linux-airgapped/ ↩︎
https://goharbor.io/docs/1.10/administration/configuring-replication/create-replication-endpoints/ ↩︎